/**
 *	@author: Kathleen Go
 *	date created: February 11, 2006
 *	version: 1.0
 *  modified: May 2, 2006
 */

package text.learning;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Iterator;

import text.obj.TExtChunk;

public class TExtChunkAligner{
	
	private Hashtable alignedWords;
	private Hashtable alignedChunks;
	private Vector vAlignedChunkSource;
	private Vector vAlignedChunkTarget;
	private TExtChunkLexicon chunkLex;
	private Vector vFunctionTarget;
	private boolean bFinished;
	private String strMapping;
	private Vector vFunctionSource;

	public TExtChunkAligner(boolean isFilipino, Vector vFunctionWords){
		alignedChunks = new Hashtable();
		vAlignedChunkSource = new Vector(1);
		vAlignedChunkTarget = new Vector(1);
		if(isFilipino)
			chunkLex = new TExtChunkLexicon('e');
		else
			chunkLex = new TExtChunkLexicon('f');
			
		if(isFilipino){
			vFunctionSource = (Vector)vFunctionWords.get(0);
			vFunctionTarget = (Vector)vFunctionWords.get(1);
		}
		else{
			vFunctionSource = (Vector)vFunctionWords.get(1);
			vFunctionTarget = (Vector)vFunctionWords.get(0);
		}
	}

	public TExtChunkAligner(boolean isFilipino, Vector vFunctionWords, Hashtable alignedWords){
		this.alignedWords = alignedWords;
		alignedChunks = new Hashtable();
		vAlignedChunkSource = new Vector(1);
		vAlignedChunkTarget = new Vector(1);
		if(isFilipino)
			chunkLex = new TExtChunkLexicon('e');
		else
			chunkLex = new TExtChunkLexicon('f');
		
		if(isFilipino){
			vFunctionSource = (Vector)vFunctionWords.get(0);
			vFunctionTarget = (Vector)vFunctionWords.get(1);
		}
		else{
			vFunctionSource = (Vector)vFunctionWords.get(1);
			vFunctionTarget = (Vector)vFunctionWords.get(0);
		}
	}

	/**	Finds the alignment of chunks between the chunks ({@link TExtChunk}) of a Source sentence
	 * 		and the chunks ({@link TExtChunk}) of a Target sentence.
	 * 
	 *	Returns the {@link Hashtable} of aligned chunks.
	 *
	 *	@param vChunkSource a {@link Vector} representing the Source chunks (TExtChunk) to be aligned
	 *	@param vChunkTarget a {@link Vector} representing the Target chunks (TExtChunk) to be aligned
	 *	@param alignedWords a {@link Hashtable} containing the alignment of the chunks' tokens
	 *	@return the {@link Hashtable} containing the aligned chunks
	 *			a chunk from the source sentence is stored as a KEY
	 *			a KEY entry is a {@link TExtChunk}
	 *			corresponding VALUEs are the matched chunks in the target sentence
	 *			a VALUE entry is a {@link Vector} consisting of at least 1 {@link TExtChunk}
	 */
	public Hashtable alignChunks(Vector vChunkSource, Vector vChunkTarget, Hashtable alignedWords){
		alignedChunks.clear();
		vAlignedChunkSource.clear();
		vAlignedChunkTarget.clear();
		this.alignedWords = alignedWords;
		bFinished = false;
		
		Vector vAlignedChunk = new Vector();
		Vector vChunkSourceTemp = (Vector)vChunkSource.clone();
		Vector vChunkTargetTemp = (Vector)vChunkTarget.clone();
		Vector vSourceTargetTemp;
		Vector vResult;
		int arrScores[][];
		int arrContent[][];
		int nSourceSize = vChunkSourceTemp.size();
		int nTargetSize = vChunkTargetTemp.size();

		vSourceTargetTemp = useExistingChunksDB(vChunkSourceTemp, vChunkTargetTemp);
		
		if(!bFinished){
			vChunkSourceTemp = (Vector)vSourceTargetTemp.get(0);
			vChunkTargetTemp = (Vector)vSourceTargetTemp.get(1);
			
			nSourceSize = vChunkSourceTemp.size();
			nTargetSize = vChunkTargetTemp.size();
			
			arrScores = new int[nSourceSize][nTargetSize];
			arrContent = new int[nSourceSize][nTargetSize];
			
			for(int i = 0; i < nSourceSize; i++){
				vResult = (Vector)alignFromAlignedWords((TExtChunk)vChunkSourceTemp.get(i), vChunkTargetTemp, 'a', false);
				arrScores[i] = (int[])vResult.get(0);
				arrContent[i] = (int[])vResult.get(1);
			}
			filterChunks(vChunkSourceTemp, vChunkTargetTemp, arrScores, arrContent);
		}
		makeStringMapping(vChunkSource, vChunkTarget);
		convertAlignedChunksToHash();
		
		return alignedChunks;
	}
	
	/**	This function produces a the mapping of the indices of the aligned chunks.
	 *	The given the Source (vChunkSource) and Target (vChunkTarget) chunks that represents
	 *		the original order of chunk.  The Vectors of aligned Source chunks and Target
	 *		chunks are compared to the former two chunks to get the index of each aligned
	 *		Source and and its corresponding Target in the original order.
	 */
	protected void makeStringMapping(Vector vChunkSource, Vector vChunkTarget){
		Vector vSIndices = new Vector(1);
		Vector vTIndices = new Vector(1);
		StringBuffer sbMapping = new StringBuffer();
		
		int nCtr = 0;
		for(Iterator itSOrig = vChunkSource.iterator(); itSOrig.hasNext(); ){
			int sCtr = 0;
			TExtChunk cSOrig = (TExtChunk)itSOrig.next();
			for(Iterator itSNew = vAlignedChunkSource.iterator(); itSNew.hasNext(); ){
				TExtChunk cSNew = (TExtChunk)itSNew.next();
				
				if(!(vSIndices.contains(new Integer(sCtr))) && cSOrig.toString().compareTo(cSNew.toString()) == 0
					&& cSOrig.domain().compareTo(cSNew.domain()) == 0
					&& cSOrig.getCompoundIdentifier().compareTo(cSNew.getCompoundIdentifier()) == 0){
						vSIndices.add(new Integer(sCtr));
						break;
				}
				sCtr++;
			}
			TExtChunk cTNew = (TExtChunk)vAlignedChunkTarget.get(sCtr);
			
			int tCtr = 0;
			for(Iterator itTOrig = vChunkTarget.iterator(); itTOrig.hasNext(); ){
				TExtChunk cTOrig = (TExtChunk)itTOrig.next();
				if(!(vTIndices.contains(new Integer(tCtr))) && cTOrig.toString().compareTo(cTNew.toString()) == 0
					&& cTOrig.domain().compareTo(cTNew.domain()) == 0
					&& cTOrig.getCompoundIdentifier().compareTo(cTNew.getCompoundIdentifier()) == 0){
						vTIndices.add(new Integer(tCtr));
						break;
				}
				tCtr++;
			}
			
			sbMapping = sbMapping.append(nCtr + "-" + tCtr + ";");
			nCtr++;
		}
		
		strMapping = sbMapping.toString();
	}
	
	/**	This returns the index mapping of the aligned Source and Target chunks.
	 *	
	 *	Returns a {@String} representing index mapping of the alignment of the Source and
	 *		Target chunks handled by a TExtChunkAligner object.
	 *
	 *	@return the {@String} representing the index mapping of the alignment of the Source
	 *		and Target chunks handled by a TExtChunkAligner object.
	 */
	public String getStringMapping(){
		return strMapping;
	}
	
	/**	Returns the {@Vector} of aligned Source chunks and the Vector of aligned
	 *		Target chunks handled by a TExtChunkAligner object.
	 *
	 *	@return the {@Vector} of aligned Source chunks and the Vector of aligned
	 *		Target chunks handled by a TExtChunkAligner object
	 *			Index 0 is a Vector that contains the Vector of aligned Source chunks.
	 *			Index 1 is a Vector that contains the Vector of aligned Target chunks.
	 */
	public Vector getCurrentAlignedChunks(){
		Vector vAlignedChunks = new Vector(2);
		vAlignedChunks.add(vAlignedChunkSource);
		vAlignedChunks.add(vAlignedChunkTarget);
		return vAlignedChunks;
	}

	/**	This function determines the final alignment on the remaining Source (vChunkSourceTemp)
	 *		and Target (vChunkTargetTemp) chunks.
	 *	arrScores[][] represents the number of aligned tokens between each Source and Target
	 *		chunk pair.  arrContent[][] represents the number of aligned tokens between
	 *		each Source and Target chunk pair.
	 *	This function makes use of arrContent to align the Source and Target chunk with the
	 *		most number of aligned non-function word while arrScores serves as a tie-breaker
	 *		in case ties are encountered.
	 */
	public void filterChunks(Vector vChunkSourceTemp, Vector vChunkTargetTemp, int[][] arrScores, int[][] arrContent){
		int nSourceSize = vChunkSourceTemp.size();
		int nTargetSize = vChunkTargetTemp.size();
		int nHighest[] = new int[nSourceSize];
		int nRemove;
		int nHighScore;
		int nHighestContent[] = new int[nSourceSize];
		int nCurrent;
		int nRef;
		int nTracker  = 0;
		
		while(nTracker < nTargetSize){
			for(int i = 0; i < nTargetSize; i++){
				for(int k = 0; k < nSourceSize; k++){
					for(int j = 0; j < nTargetSize; j++){
						nCurrent = arrContent[k][j];
						nRef = arrContent[k][nHighestContent[k]];
						if(j == 0)
							nHighestContent[k] = j;
						else if(nCurrent > nRef)
							nHighestContent[k] = j;
						else if(nCurrent == nRef && nCurrent != -1 && arrScores[k][j] > arrScores[k][nHighestContent[k]])
							nHighestContent[k] = j;
					}
				}
				
				nRemove = -1;
				nHighScore = -1;
				for(int j = 0; j < nSourceSize; j++){
					if(nHighestContent[j] == i && (arrContent[j][i] > nHighScore)){
						nRemove	= j;
						nHighScore = arrScores[j][i];
					}
				}
				
				if(nRemove != -1){
					nTracker++;
					vAlignedChunkSource.add(vChunkSourceTemp.get(nRemove));
					vAlignedChunkTarget.add(vChunkTargetTemp.get(i));
					vChunkSourceTemp.set(nRemove, null);
					
					for(int j = 0; j < nSourceSize; j++)
						arrContent[j][i] = -1;
					for(int j = 0; j < nTargetSize; j++)
						arrContent[nRemove][j] = -1;
					
					vChunkTargetTemp.set(i, null);
				}			
			}
		}
	}

	/**	Given the Vector of Source chunks (vSource) and Vector of Target chunks (vTarget),
	 *		this function attemps to align as many as possible by checking the Chunks DB
	 *		for existing alignments. This function handles exact matches.
	 *	Returns the {@link Hashtable} of aligned chunks.
	 *
	 *	@param vSource a {@link Vector} representing the Source chunks (TExtChunk) to be aligned
	 *	@param vTarget a {@link Vector} representing the Target chunks (TExtChunk) to be aligned
	 *	@return the {@link Vector} containing the unaligned chunks
	 *		Index 0 is the Vector that contains the remaining unaligned Source chunks
	 *		Index 1 is the Vector that contains the remaining unaligned Target chunks
	 */
	public Vector useExistingChunksDB(Vector vSource, Vector vTarget){
		String strSource;
		Vector vTargetLookUp = null;
		Vector vCandidateTarget = new Vector(1);
		Vector vSourceTarget = new Vector(1);
		int nAlignedSource = 0;
		int nOrigSource = vSource.size();
		TExtChunk chunkSource;
		TExtChunk chunkTarget;
		int nTargetSize;
		int nLookUpSize;
	
		int nOffsetS = 0;
		Vector vRemovedTarget = new Vector(1);
		Vector vRemovedIndS = new Vector(1);
		Vector vRemovedIndT = new Vector(1);
		Vector vRemainingIndT = new Vector(vTarget.size());
		
		for(int i = 0; i < vTarget.size(); i++)
			vRemainingIndT.add(new Integer(i));
		
		for(int i = 0; i < vSource.size(); i++){
			chunkSource = (TExtChunk)vSource.get(i);
			strSource = chunkSource.toString();
			vTargetLookUp = chunkLex.lookup(strSource, chunkSource.getCompoundIdentifier());
			nTargetSize = vTarget.size();
			for(int j = 0; j < nTargetSize; j++){
				chunkTarget = (TExtChunk)vTarget.get(j);
				if(vTargetLookUp != null){
					nLookUpSize = vTargetLookUp.size();
					for(int k = 0; k < nLookUpSize; k++)
						if(isChunkEqual((TExtChunk)vTargetLookUp.get(k), chunkTarget)){
							vCandidateTarget.add(chunkTarget);
							vRemovedTarget.add(new Integer(j));
						}
				}
			}
			if(vCandidateTarget.size() > 0){
				int nRemovedTarget;
				int nRemovedTIndex;
				if(vCandidateTarget.size() > 1){
					Vector vCandTemp = alignFromAlignedWords(chunkSource, (Vector)vCandidateTarget.clone(), 'b', false);
					vCandidateTarget.clear();
					vCandidateTarget.add(vCandTemp.get(0));
					nRemovedTIndex = ((Integer)(vRemovedTarget.get(((Integer)vCandTemp.get(1)).intValue()))).intValue();
//
					vCandTemp = null;
//
				}
				else
					nRemovedTIndex = ((Integer)(vRemovedTarget.get(0))).intValue();
				vAlignedChunkSource.add(chunkSource);
				vAlignedChunkTarget.add((TExtChunk)vCandidateTarget.get(0));
				
				nAlignedSource++;
				vSource.remove(i);
				vRemovedIndS.add(new Integer(i+nOffsetS));
				nOffsetS++;
				vTarget.remove(vCandidateTarget.get(0));
				Vector vRemainingTDummy = (Vector)vRemainingIndT.clone();
				nRemovedTarget = ((Integer)(vRemainingTDummy.get(nRemovedTIndex))).intValue();
				vRemovedIndT.add(new Integer(nRemovedTarget));
				vRemovedTarget = new Vector(1);
				vRemainingIndT.remove(nRemovedTIndex);
				i--;
//
				vRemainingTDummy = null;
//
			}

			vCandidateTarget.clear();
		}
		
		if(nAlignedSource == nOrigSource)
			bFinished = true;
//			
		strSource = null;
		vTargetLookUp = null;
		vCandidateTarget = null;
//
		vSourceTarget.add(vSource);
		vSourceTarget.add(vTarget);
		vSourceTarget.add(vRemovedIndS);
		vSourceTarget.add(vRemovedIndT);
		return vSourceTarget;
	}

	/**	Checks whether the two chunks (chunkLookUp and chunkTarget) have the tokens.
	 */
	public boolean isChunkEqual(TExtChunk chunkLookUp, TExtChunk chunkTarget){
		Object tokenLU;
		Object tokenT;
		
		if(chunkLookUp.size() != chunkTarget.size())
			return false;
		for(Iterator itLU = chunkLookUp.iterator(), itT = chunkTarget.iterator(); itLU.hasNext(); ){
			tokenLU = itLU.next();
			tokenT = itT.next();
			
			if((tokenLU instanceof TExtChunk && tokenT instanceof String) || 
				(tokenLU instanceof String && tokenT instanceof TExtChunk) || 
					(tokenLU.toString()).compareToIgnoreCase(tokenT.toString()) != 0)
						return false;
		}
		return true;		
	}

	/**	Given a Source chunk ({@TExtChunk} chunkSource) and a {@Vector} of Target chunks
	 *		(vTarget), this function compares chunkSource with each element of vTarget such
	 *		that for each Source-Target pair, their alignment will be scored by counting
	 *		the number of aligned tokens they have.  For each pair, there are two scores
	 *		such that one score measures the number of aligned important words while the
	 *		other measures the score of the all alignments.  As each Source-Target chunk
	 *		pair is compared, a Source-to-Target alignment array is constructed to show
	 *		which Source token is aligned to which Target token by recording their indices.
	 *		A Target-to-Source alignment array is also constructed to show which Target
	 *		token is aligned to which Source token by recording their indices.
	 *
	 *	@param chunkSource a {@link TExtChunk} representing the Source chunk (TExtChunk) to be aligned
	 *	@param vTarget a {@link Vector} representing the Target chunks (TExtChunk) to be aligned
	 *	@param cCallerFunc a character indicating what is needed by the calling function.  A value of 'a' means that the caller needs the scores of all pairs.  A value 'b' means that
	 *		the caller needs the Target chunk that is closely aligned to the given Source chunk.
	 *	@param bFromSplitter a boolean indicating whether the caller needs the Source-to-Target and Target-to-Source alignment matrices.
	 *	@return the {@link Vector} containing comparison results depending on the value of cCallerFunc
	 *		If cCallerFunc == 'a'
	 *				Index 0 is the Target chunk that is the most closely aligned to chunkSource
	 *				Index 1 is the index of the object in Index 0 among the given Target chunks
	 *		If cCallerFunc == 'b'
	 *				Index 0 is the array of scores that measures all alignments
	 *				Index 1 is the array of scores that measures the alignments of important words
	 *			If bFromSplitter == true
	 *				Index 2 is the Source-to-Target alignment matrix of the given Source chunk and Target chunks
	 *				Index 3 is the Target-to-Source alignment matrix of the given Source chunk and Target chunks
	 */
	public Vector alignFromAlignedWords(TExtChunk chunkSource, Vector vTarget, char cCallerFunc, boolean bFromSplitter){
		boolean bFound;
		Vector vTokenSourceCandidate = new Vector();
		Vector vCandidateTarget;
		int nVectorSize;
		int nScore[] = new int[vTarget.size()];
		int nContent[] = new int[vTarget.size()];
		int nMaxIndex = 0;
		int nTargetSize = vTarget.size();
		int nChunkTargetSize;
		int nSourceCandidateSize;
		int nCandidateSize;
		String strTargetTemp = "";
		int nSourceSize = chunkSource.size();
		TExtChunk chunkTarget;
		Object strSourceToken;
		boolean bMod = false;
		boolean bMod2 = false;
		String strChunkTargetToken;
		Vector vSourcePOVMap = new Vector(1);
		Vector vTargetPOVMap = new Vector(nTargetSize);
		Vector vDummySrcPOVMap;
		Vector vDummyTarPOVMap;
		boolean bChangeScores = false;
		
		for(int i = 0; i < nTargetSize; i++){
			nScore[i] = 0;
			nContent[i] = 0;
		}
		
		if(nSourceSize == 0){
			nSourceSize = 1;
			bMod = true;
		}

		for(int i = 0; i < nSourceSize; i++){
			vCandidateTarget = null;
			if(bMod)
				strSourceToken = chunkSource.domain();
			else
				strSourceToken = (chunkSource.get(i)).toString();
			vCandidateTarget = (Vector)alignedWords.get(strSourceToken);
			if(vCandidateTarget == null)
				vCandidateTarget = new Vector(1);
				vTokenSourceCandidate.add(vCandidateTarget);
		}

		for(int i = 0; i < nTargetSize; i++){
			chunkTarget = (TExtChunk)vTarget.get(i);
			nChunkTargetSize = chunkTarget.size();
			bMod2 = false;		
			if(nChunkTargetSize == 0){
				bMod2 = true;
				nChunkTargetSize = 1;
			}
			vDummySrcPOVMap = new Vector(nSourceSize);
			for(int j = 0; j < nSourceSize; j++)
				vDummySrcPOVMap.add(new Integer(-1));
			vDummyTarPOVMap = new Vector(nChunkTargetSize);
			for(int j = 0; j < nChunkTargetSize; j++){
				bFound = false;
				nSourceCandidateSize = vTokenSourceCandidate.size();
				for(int n = 0; n < nSourceCandidateSize && !bFound; n++){
					vCandidateTarget = (Vector)vTokenSourceCandidate.get(n);
					nCandidateSize = vCandidateTarget.size();
					for(int k = 0; k < nCandidateSize && !bFound; k++){
						strTargetTemp = (String)vCandidateTarget.get(k);
						if(bMod2)
							strChunkTargetToken = chunkTarget.domain();
						else
							strChunkTargetToken = chunkTarget.get(j).toString();
						
						if(strTargetTemp != null && strTargetTemp.compareToIgnoreCase(strChunkTargetToken) == 0
							&& !vDummyTarPOVMap.contains(new Integer(n))){
							nScore[i]++;
							if(!isFunction(strTargetTemp, false))
								nContent[i]++;
							bFound = true;
						}
						strTargetTemp = "";
					}
					if(bFound){
						vDummyTarPOVMap.add(new Integer(n));
						vDummySrcPOVMap.setElementAt(new Integer(j), n);
					}
				}
				if(!bFound && chunkTarget.size() > 0 && isFunction(chunkTarget.get(j).toString(), false)){
					nScore[i]++;
					bFound = true;
					vDummyTarPOVMap.add(new Integer(-999));
				}
				if(!bFound)
					vDummyTarPOVMap.add(new Integer(-1));
				if(bFromSplitter && !bFound)
					bChangeScores = true;
			}
				
			vDummySrcPOVMap = recognizeFcnWords(vDummySrcPOVMap, chunkSource);
			vSourcePOVMap.add((Vector)vDummySrcPOVMap.clone());
			vTargetPOVMap.add((Vector)vDummyTarPOVMap.clone());
			if(bChangeScores){
				nScore[i] = -1;
				nContent[i] = -1;
				bChangeScores = false;
			}
		}
	
//
		vTokenSourceCandidate = null;
		vCandidateTarget = null;
//

		Vector vReturn;
		if(cCallerFunc == 'b'){
			for(int i = 0; i < nScore.length; i++)
				if(nScore[i] > nScore[nMaxIndex])
					nMaxIndex = i;
			if(nMaxIndex == -1)
				return null;
			
			vReturn = new Vector(2);
			vReturn.add(vTarget.get(nMaxIndex));
			vReturn.add(new Integer(nMaxIndex));
			return vReturn;
		}
		else{
			vReturn = new Vector(4);
			vReturn.add(nScore);
			vReturn.add(nContent);
			if(bFromSplitter){
				vReturn.add(vSourcePOVMap);
				vReturn.add(vTargetPOVMap);
			}
			return vReturn;
		}
	}

	/**	Given a Source chunk (chunkSource) and its Source-to-Target alignment matrix, this
	 *		function determines which among the unaligned tokens (-1 value in the alignment
	 *		matrix) are non-important words and changes their values to -999 indicating that
	 *		they don't need to have a corresponding Target token.
	 *	Returns the modified Source-to-Target alignment matrix.
	 */
	protected Vector recognizeFcnWords(Vector vDummySrcPOVMap, TExtChunk chunkSource){
		if(chunkSource.size() > 0){
			int nDummySize = vDummySrcPOVMap.size();
			for(int i = 0; i < nDummySize; i++)
				if(((Integer)vDummySrcPOVMap.get(i)).intValue() == -1)
					if(isFunction((chunkSource.get(i)).toString(), true))
						vDummySrcPOVMap.setElementAt(new Integer(-999), i);
		}
		return vDummySrcPOVMap;
	}

	/**	Checks if the given word (strWords) in a given language (isSource)
	 *		is a non-important word.
	 */
	public boolean isFunction(String strWords, boolean isSource){
		boolean isFunction = false;
		Vector vFunction;
		
		if(isSource)
			vFunction = vFunctionSource;
		else
			vFunction = vFunctionTarget;
			
		for(Iterator it = vFunction.iterator(); it.hasNext() && !isFunction; )
			if(strWords.compareToIgnoreCase((String)it.next()) == 0)
				isFunction = true;
		return isFunction;
	}

	/**	This function loops through the Vector of aligned Source chunks to look for
	 *		the same chunks occuring twice.  One of the duplicating chunks is removed
	 *		and its corresponding Target will be combined with the other's Vector of
	 *		Target chunks.
	 *	This also converts the Vector of aligned Source and Target to a Hashtable.
	 */
	public void convertAlignedChunksToHash(){
		TExtChunk chunkSourceTemp;
		TExtChunk chunkTargetTemp;
		Vector vChunkTargetTemp;
		Vector vChunkTargetInHash;
		int nIndex;
		int nAlignedSize = vAlignedChunkSource.size();
		Vector includedSource = new Vector(nAlignedSize);
		Vector vFilteredSource = new Vector(nAlignedSize);
		Vector vFilteredTarget = new Vector(nAlignedSize);
		
		for(int i = 0; i < nAlignedSize; i++){
			chunkSourceTemp = (TExtChunk)vAlignedChunkSource.get(i);
			chunkTargetTemp = (TExtChunk)vAlignedChunkTarget.get(i);

			nIndex = isIncludedChunk(includedSource, chunkSourceTemp);
			if(nIndex == -1){
				vChunkTargetTemp = new Vector(1);
				vChunkTargetTemp.add(chunkTargetTemp);
				includedSource.add(chunkSourceTemp);
				
				vFilteredSource.add(chunkSourceTemp);
				vFilteredTarget.add(vChunkTargetTemp);
			}
			else{
				vChunkTargetInHash = (Vector)vFilteredTarget.get(nIndex);
				vChunkTargetInHash.add(chunkTargetTemp);
				vFilteredTarget.remove(nIndex);
				vFilteredTarget.insertElementAt(vChunkTargetInHash, nIndex);
			}
		}
		alignedChunks.clear();
		alignedChunks.put(vFilteredSource, vFilteredTarget);
	}

	/**	This function checks the given Source chunk (vChunkSourceTemp) was already
	 *		encountered by looking at the Vector of encountered Source chunks
	 *		(vIncludedSource).
	 *	Returns the index of the equivalent vChunkSourceTemp's equivalent chunk in
	 *		vIncludedSource.
	 */
	public int isIncludedChunk(Vector vIncludedSource, TExtChunk vChunkSourceTemp){
		int nIndex = -1;
		TExtChunk vIncluded;
		Object SourceTemp;
		Object Included;
		boolean bStop;
		int nIncluded = vIncludedSource.size();
		int nChunkSourceTemp = vChunkSourceTemp.size();
		
		for(int j = 0; j <  nIncluded && nIndex == -1; j++){
			vIncluded = (TExtChunk)vIncludedSource.get(j);
			int nIncludedSize = vIncluded.size();
			if(nIncludedSize == nChunkSourceTemp){
				bStop = false;
				if(nIncludedSize==0 && nChunkSourceTemp == 0){
					SourceTemp = vChunkSourceTemp.domain();
					Included = vIncluded.domain();
					if((SourceTemp.toString()).compareTo(Included.toString()) != 0)
						bStop = true;
				}
				else{
					for(int k = 0; k < nIncludedSize && !bStop; k++){
						SourceTemp = vChunkSourceTemp.get(k);
						Included = vIncluded.get(k);
						
						if((SourceTemp.toString()).compareTo(Included.toString()) != 0)
							bStop = true;
					}
					
					if(!bStop && (vChunkSourceTemp.domain()).compareTo(vIncluded.domain()) != 0)
						bStop = true;
				}
				if(!bStop)
					nIndex = j;
			}
		}
		return nIndex;
	}
}